package com.lj.demo.springbootshirojwt.shiro;

import com.lj.demo.springbootshirojwt.exception.AuthorizationException;
import com.lj.demo.springbootshirojwt.util.Constants;
import com.lj.demo.springbootshirojwt.util.HttpRequestUtil;
import com.lj.demo.springbootshirojwt.util.JWTToken;
import com.lj.demo.springbootshirojwt.util.JWTUtil;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * Title: 用户realm
 * Description:
 * Date: 2019年06月26日 14:30
 *
 * @author lvjie@hiynn.com
 * @version 1.0
 * Significant Modify：
 * Date                  Author                 Content
 * =================================================================
 * 2019年06月26日         lvjie@hiynn.com         创建文件,实现基本功能
 * =================================================================
 */
@Component
public class UserRealmByRedis extends AuthorizingRealm {

    private static final Logger LOGGER = LoggerFactory.getLogger(UserRealmByRedis.class);

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private HttpServletRequest request;

    /**
     * 校验token是否是自定义的token
     * @param token
     * @return
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JWTToken;
    }

    /**
     * 权限校验
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        LOGGER.info("开始鉴权");
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        String token = principals.getPrimaryPrincipal().toString();
        info.addRoles(JWTUtil.getRoles(token));
        info.addStringPermissions(JWTUtil.getPermissions(token));
        return info;
    }

    /**
     * 登录认证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        JWTToken jwtToken = (JWTToken) authenticationToken;
        String token = jwtToken.getPrincipal().toString();
        String userName = JWTUtil.getUserName(token);
        //获取密码
        String key = userName + Constants.REDIS_KEY_TOKEN + "_" + HttpRequestUtil.getIpAdrress(request);
        //检验token是否有效
        Object tokenFromRedis = redisTemplate.opsForValue().get(key);
        if (null == tokenFromRedis || !Objects.equals(token,tokenFromRedis)){
            throw new AuthorizationException("token已失效请重新登录");
        }
        //更改redis到期时间
        redisTemplate.opsForValue().set(userName+Constants.REDIS_KEY_TOKEN+"_"+ HttpRequestUtil.getIpAdrress(request)
                ,token,Constants.REDIS_TOKEN_EXPIRE_TIME, TimeUnit.MILLISECONDS);
        return new SimpleAuthenticationInfo(token, token, getName());
    }
}
